package {
	import flash.display.*;
	import flash.events.*;
	import flash.geom.*;
	import flash.filters.*;
	import flash.utils.getTimer;
	import org.flashdevelop.utils.FlashConnect;

	public class Detector 
	{
		private var s:BitmapData;
		private var r:BitmapData;
		private var blocks:Array;
		private var maxRatioDiff:Number = 0.5;
		private var minimumObjectSize:Number = 300;
		private var maximumObjectSize:Number = 650;
		private var time:int;
		private var prevTime:int;

		
		public function Detector() 
		{
		}

		public function proccess(s:BitmapData):Array 
		{
			var r1:BitmapData,r2:BitmapData,r3:BitmapData,r4:BitmapData;
			r1 = getDiffImage(s);
			var blocks:Array = getBlocks(r1);
			r2 = drawBlocks(r1,blocks);
			r3 = drawBlobs(s);
			return [r1, r2, r3];
			
			
		}
		public function get fps():Number
		{
			time = getTimer();
            var res:Number = Math.floor(1000 / (time - prevTime));
            prevTime = time;
			return res;
		}

		public function getDiffImage(s:BitmapData):BitmapData 
		{
			var r:BitmapData = new BitmapData(s.width,s.height);
			var r2:BitmapData = new BitmapData(s.width,s.height);
			var rect:Rectangle = new Rectangle(0,0,s.width,s.height);
			var pt:Point = new Point(0,0);

			r.draw(s);
			r2.draw(s);
			
			var mtx:Matrix = new Matrix();
			mtx.translate(2,0);
			r.draw(s, mtx, new ColorTransform(), BlendMode.DIFFERENCE);
			mtx.translate(-2,2);
			r2.draw(s, mtx, new ColorTransform(), BlendMode.DIFFERENCE);

			r.copyPixels(r, new Rectangle(2,0,2,s.height), pt);
			r2.copyPixels(r2, new Rectangle(0,2,s.width,2), pt);

			r.draw(r2, new Matrix(), new ColorTransform(), BlendMode.ADD);

			var filter:ConvolutionFilter = new ConvolutionFilter(3,3,
			[0.1,0.1,0.1,
			0.1,0.1,0.1,
			0.1,0.1,0.1]);
			r.applyFilter(r,rect,pt,filter);
			r.threshold(r, rect, pt, "<", 0xff111111, 0xff000000);
			r.threshold(r, rect, pt, "!=", 0xff000000, 0xffffffff);
			return r;
		}

		public function getBlocks(s:BitmapData):Array 
		{
			blocks = new Array();
			var o:Object;
			var size:uint;
			var r:BitmapData=new BitmapData(s.width,s.height);
			var i:int;
			r.draw(s);
			
			var rect1:Rectangle, rect2:Rectangle;
			
			while (true) 
			{
				i++;
				if (i > 1000) 
				{
					break;
				}
				rect1 = r.getColorBoundsRect(0xffffffff, 0xffffffff);
				
				if (rect1.isEmpty()) 
				{
					break;
				}

				var x:Number = rect1.x;
				var ratioDiff:Number;
				for (var y:uint = rect1.y; y < rect1.y + rect1.height; y++) 
				{
					if (r.getPixel32(x, y) == 0xffffffff) 
					{
						r.floodFill(x, y, 0xffff00ff);
						rect2=r.getColorBoundsRect(0xffffffff,0xffff00ff);
						size = rect2.width * rect2.height;
						if (size > minimumObjectSize && size < maximumObjectSize) 
						{
							ratioDiff = Math.abs(1 - (rect2.width / rect2.height));
							
							//FlashConnect.trace(ratioDiff);
							if (ratioDiff < maxRatioDiff)
							{
								o = new Object();
								o.size=size;
								o.rect=rect2;
								o.bmpd=new BitmapData(o.rect.width,o.rect.height);
								o.bmpd.copyPixels(r, o.rect, new Point(0,0));
								blocks.push(o);	
							}
						}
						r.floodFill(x, y, 0xff00ffff);
					}
				}
			}
			
			return blocks;
			
		}
			
		public function drawBlocks(r:BitmapData,blocks:Array=null):BitmapData
		{
			if (blocks == null) blocks = getBlocks(r);
			
			var sp:Sprite = new Sprite();
			var g:Graphics=sp.graphics;
			var i:uint=0;
			//var blocks:Array = getBlocks(r);
			var print:String = '';
			for (i = 0; i < blocks.length; i ++) 
			{
				g.lineStyle(0,0x00FF00);
				g.drawRect(blocks[i].rect.x, blocks[i].rect.y, blocks[i].rect.width, blocks[i].rect.height);
				print = print + ', ' + blocks[i].size;
			}
			//FlashConnect.trace(print);
			r.draw(sp);
			return r;
		}

		public function drawBlobs(s:BitmapData):BitmapData 
		{
			var sp:Sprite = new Sprite();
			var g:Graphics = sp.graphics;
			var r:BitmapData=new BitmapData(s.width,s.height);
			r.draw(s);
			var pts:Array;
			var b:Object;
			var mid1:Point,mid2:Point;
			var x:int,y:int,i:uint,j:uint;
			for (i = 0; i < blocks.length; i++) 
			{
				pts = [];
				b = blocks[i];
				for (y = 0; y < b.rect.height; y += 5) 
				{
					for (x = 0; x < b.rect.width; x += 1) 
					{
						if (b.bmpd.getPixel(x, y) == 0xff00ff) 
						{
							pts.push(new Point(x,y));
							break;
						}
					}
				}
				for (y = b.rect.height -1; y >= 0; y -= 5) 
				{
					for (x = b.rect.width - 1; x >= 0; x -= 1) 
					{
						if (b.bmpd.getPixel(x, y) == 0xff00ff) 
						{
							pts.push(new Point(x,y));
							break;
						}
					}
				}
				g.beginFill(0xFF0000,0.2);
				g.lineStyle(0,0xFF0000);
				for (j = 0; j < pts.length; j ++) 
				{
					if (j == 0) 
					{
						mid1 = Point.interpolate(pts[j], pts[(j + 1) % pts.length], 0.5);
						g.moveTo(b.rect.x + mid1.x, b.rect.y + mid1.y);
					}
					mid2 = Point.interpolate(pts[(j + 2) % pts.length], pts[(j + 1) % pts.length], 0.5);
					g.curveTo(b.rect.x + pts[(j + 1) % pts.length].x, b.rect.y + pts[(j + 1) % pts.length].y, b.rect.x + mid2.x, b.rect.y + mid2.y);
				}
				g.endFill();
			}
			r.draw(sp);
			return r;
		}

	}
}